from processing.wrapers import cpu_run, cpu_run_instruction, handle_interruption,\
    cpu_trigger_interruption, pcb_to_ready, load_pcb_to_cpu, create_pcb,\
    io_finish, set_kernel_mode, set_user_mode, idle_mode
from main.model.devices.cpu import CPU
from main.model.logic.interruption import InterruptionManager
from main.model.logic.kernel import Kernel
from main.model.logic.input_output import InOut
from main.model.logic.usher import Usher

def wait_original(listener, spy):
    def callback(original):
        def wraper(owner, *originalarg, **originalkarg):
            spy(listener, original, owner, *originalarg, **originalkarg)
        return wraper
    return callback

def wrap_method(cls, method_name, wait_orinial):
    wraper = wait_orinial(cls.__dict__[method_name])
    try:
        cls.__dict__[method_name] = wraper
    except TypeError:
        setattr(cls, method_name, wraper)

def prototype(listener):
    wrap_method(CPU, "run", wait_original(listener, cpu_run))
    wrap_method(CPU, "run_instruction", wait_original(listener, cpu_run_instruction))
    wrap_method(CPU, "trigger", wait_original(listener, cpu_trigger_interruption))
    wrap_method(InterruptionManager, "handle", wait_original(listener, handle_interruption))
    wrap_method(Kernel, "send_to_ready", wait_original(listener, pcb_to_ready))
    wrap_method(Kernel, "load_to_cpu", wait_original(listener, load_pcb_to_cpu))
    wrap_method(Kernel, "load", wait_original(listener, create_pcb))
    wrap_method(Kernel, "sleep_on_idle", wait_original(listener, idle_mode))
    wrap_method(InOut, "send_to_ready", wait_original(listener, io_finish))
    wrap_method(Usher, "set_kernel_mode", wait_original(listener, set_kernel_mode))
    wrap_method(Usher, "set_user_mode", wait_original(listener, set_user_mode))
    
    